package com.xiaoyy.core.oplog.integration.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DatePattern;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.xiaoyy.core.common.cache.CacheConst;
import com.xiaoyy.core.common.enums.AuthStatusEnum;
import com.xiaoyy.core.common.enums.BoolEnum;
import com.xiaoyy.core.common.enums.OpTypeEnum;
import com.xiaoyy.core.common.vo.*;
import com.xiaoyy.core.common.exception.AppException;
import com.xiaoyy.core.config.util.FieldChangeUtil;
import com.xiaoyy.core.config.util.RedisUtil;
import com.xiaoyy.core.dict.integration.DictIntegration;
import com.xiaoyy.core.oplog.dao.model.Oplog;
import com.xiaoyy.core.oplog.dao.model.OplogApi;
import com.xiaoyy.core.oplog.dao.model.OplogTableChange;
import com.xiaoyy.core.oplog.integration.OplogIntegration;
import com.xiaoyy.core.oplog.service.OplogApiService;
import com.xiaoyy.core.oplog.service.OplogService;
import com.xiaoyy.core.oplog.service.OplogTableChangeService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;

@Service
public class OplogIntegrationImpl implements OplogIntegration {
    @Autowired
    RedisUtil redisUtil;
    @Autowired
    OplogService oplogService;
    @Autowired
    OplogApiService oplogApiService;
    @Autowired
    OplogTableChangeService oplogTableChangeService;
    @Autowired
    DictIntegration dictIntegration;
    @Override
    public Long saveOpLog(OplogVO oplogVO,Object obj) {
        String accessToken = oplogVO.getAccessToken();
        if (StringUtils.isNotBlank(accessToken)){
            String redisKey= CacheConst.ACCESS_TOKEN+":"+accessToken;
            if (redisUtil.hasKey(redisKey)) {
                SessionInfo sessionInfo = (SessionInfo) redisUtil.get(redisKey);
                if (sessionInfo != null) {
                    oplogVO.setOpUserId(sessionInfo.getUserId());
                    oplogVO.setOpName(sessionInfo.getFullName());
                    oplogVO.setClientId(sessionInfo.getClientId());
                    oplogVO.setUserType(sessionInfo.getUserType());
                    oplogVO.setEquipmentId(sessionInfo.getEquipmentId());
                    oplogVO.setLoginType(sessionInfo.getLoginType());
                    oplogVO.setEquipmentType(sessionInfo.getEquipmentType());
                    oplogVO.setOpenId(sessionInfo.getOpenId());
                    oplogVO.setSystemCode(sessionInfo.getSystemCode());
                    oplogVO.setSystemName(sessionInfo.getSystemName());
                    oplogVO.setVersion(sessionInfo.getVersion());
                }
            }
        }
        // 操作时间
        oplogVO.setOpTime(new Date());
        int dateym = Integer.parseInt(DatePattern.PURE_DATE_FORMAT.format(new Date()).substring(0,6));
        //业务期 目前没有日历，直接用系统时间
        oplogVO.setDateYm(dateym);
        BeanWrapper beanWrapper =null;
        if (obj !=null){
            beanWrapper= new BeanWrapperImpl(obj);
            String dataField= oplogVO.getDataType();
            if (StringUtils.isNotBlank(dataField)){
                if (beanWrapper.isWritableProperty(dataField)){
                    if (beanWrapper.getPropertyValue(dataField)!=null) {
                        oplogVO.setDataId(beanWrapper.getPropertyValue(dataField).toString());
                    }
                }
            }

            String title = "";
            String summaryinfo ="";
            if (beanWrapper.isWritableProperty("opRouterId")){
                String routerId = "";
                if (beanWrapper.getPropertyValue("opRouterId")!=null){
                    routerId = beanWrapper.getPropertyValue("opRouterId").toString();
                }
                if (StringUtils.isNotBlank(routerId)){
                    oplogVO.setRouterId(routerId);
                }
            }
            if (beanWrapper.isWritableProperty("opOplogId")){
                String opOplogId = "";
                if (beanWrapper.getPropertyValue("opOplogId")!=null){
                    opOplogId = beanWrapper.getPropertyValue("opOplogId").toString();
                }
                if (StringUtils.isNotBlank(opOplogId)){
                    oplogVO.setUnionOplogId(Long.parseLong(opOplogId));
                }
            }
            if (beanWrapper.isWritableProperty("opFuncId")){
                String funcId = "";
                if (beanWrapper.getPropertyValue("opFuncId")!=null){
                    funcId = beanWrapper.getPropertyValue("opFuncId").toString();
                }
                if (StringUtils.isNotBlank(funcId)){
                    oplogVO.setFuncId(funcId);
                }

            }
            //设置摘要信息
            String remarks = "";
            if (StringUtils.isNotBlank(summaryinfo)){
                //转义摘要
                List<RemarksInfoVO> remarksInfoList = JSONArray.parseArray(summaryinfo, RemarksInfoVO.class);
                if (!CollectionUtils.isEmpty(remarksInfoList)){
                    for (RemarksInfoVO remarksInfo:remarksInfoList){
                        remarks =remarksInfo.getTitle()+":";
                        String value = "";
                        if (StringUtils.isNotEmpty(remarksInfo.getField())){
                            if (beanWrapper.isWritableProperty(remarksInfo.getField())){
                                value = beanWrapper.getPropertyValue(remarksInfo.getField()).toString();
                            }
                        }
                        //下拉框需要转义
                        if (StringUtils.isNotBlank(value)) {
                            if ("select".equals(remarksInfo.getType())) {
                                List<SelectVO> dictList = dictIntegration.getDict(remarksInfo.getField());
                                if (!CollectionUtils.isEmpty(dictList)) {
                                    for (SelectVO selectVO : dictList) {
                                        //字段相同转义
                                        if (value.equals(selectVO.getDictKey())){
                                            value = selectVO.getDictValue();
                                            break;
                                        }
                                    }
                                }
                            }
                        }
                        remarks = remarks+value+"；";
                    }
                }
            }
            oplogVO.setRemarks(remarks);
            //组织id
            if (beanWrapper.isWritableProperty("orgId")){
                if (null!=beanWrapper.getPropertyValue("orgId")) {
                    oplogVO.setOrgId(beanWrapper.getPropertyValue("orgId").toString());
                }
            }
            if (beanWrapper.isWritableProperty("orgCode")){
                if (null!=beanWrapper.getPropertyValue("orgCode")) {
                    oplogVO.setOrgCode(beanWrapper.getPropertyValue("orgCode").toString());
                }
            }
            if (beanWrapper.isWritableProperty("areaCode")){
                if (null!=beanWrapper.getPropertyValue("areaCode")) {
                    oplogVO.setAreaCode(beanWrapper.getPropertyValue("areaCode").toString());
                }
            }
            if (beanWrapper.isWritableProperty("personId")){
                if (null!=beanWrapper.getPropertyValue("personId")) {
                    oplogVO.setPersonId(Long.parseLong(beanWrapper.getPropertyValue("personId").toString()));
                }
            }
            if (beanWrapper.isWritableProperty("locationArea")){
                if (null!=beanWrapper.getPropertyValue("locationArea")) {
                    oplogVO.setLocationArea(beanWrapper.getPropertyValue("locationArea").toString());
                }
            }
        }
        oplogVO.setStatus(BoolEnum.TRUE.getType());
        Oplog oplog = Convert.convert(Oplog.class,oplogVO);
        oplogService.save(oplog);
        oplogVO.setOplogId(oplog.getOplogId());
        //将oplogid赋值到类中
        if (beanWrapper!=null){
            if (beanWrapper.isWritableProperty("opOplogId")) {
                beanWrapper.setPropertyValue("opOplogId", oplog.getOplogId());
            }
        }
        return oplog.getOplogId();
    }

    @Override
    public void rollback(Long oplogId, String rbUserId, String rbRemarks) {
        Oplog oplog = oplogService.getById(oplogId);
        if (oplog==null){
            throw new AppException("需要回退的日志不存在");
        }
        if (!BoolEnum.TRUE.getType().equals(oplog.getRollbackFlag())){
            throw new AppException("该业务不能回退");
        }
        if (StringUtils.isBlank(oplog.getRbStatus())||!BoolEnum.TRUE.getType().equals(oplog.getRbStatus())){
            UpdateWrapper<Oplog> upOplog = new UpdateWrapper<>();
            upOplog.lambda().set(Oplog::getRbStatus,BoolEnum.TRUE.getType())
                    .set(Oplog::getRbRemarks,rbRemarks)
                    .set(Oplog::getRbUserId,rbUserId)
                    .set(Oplog::getRbTime,new Date())
                    .eq(Oplog::getOplogId,oplogId);
            oplogService.update(upOplog);
        }
    }

    @Override
    public void finshAuth(Long oplogId, String authUserId, String authStatus, String authRemarks) {
        Oplog oplog = oplogService.getById(oplogId);
        if (oplog==null){
            return;
        }
        if (!BoolEnum.TRUE.getType().equals(oplog.getAuditFlag())){
            return;
        }
        if (StringUtils.isBlank(oplog.getAuthStatus())||!AuthStatusEnum.NODO.getType().equals(oplog.getAuthStatus())){
            UpdateWrapper<Oplog> upOplog = new UpdateWrapper<>();
            upOplog.lambda().set(Oplog::getAuthStatus,authStatus)
                    .set(Oplog::getAuthRemarks,authRemarks)
                    .set(Oplog::getAuthUserId,authUserId)
                    .set(Oplog::getAuthTime,new Date())
                    .eq(Oplog::getOplogId,oplogId);
            oplogService.update(upOplog);
        }
    }

    @Override
    @Async("oplogTaskExecutor")
    public void saveApiOpLog(OplogApiVO oplogApiVO) {
        int dateym = Integer.parseInt(DatePattern.PURE_DATE_FORMAT.format(new Date()).substring(0,6));
        //业务期 目前没有日历，直接用系统时间
        oplogApiVO.setYm(dateym);
        String accessToken = oplogApiVO.getAccessToken();
        if (StringUtils.isNotBlank(accessToken)){
            String redisKey= CacheConst.ACCESS_TOKEN+":"+accessToken;
            if (redisUtil.hasKey(redisKey)) {
                SessionInfo sessionInfo = (SessionInfo) redisUtil.get(redisKey);
                if (sessionInfo != null) {
                    oplogApiVO.setUserId(sessionInfo.getUserId());
                    oplogApiVO.setFullNme(sessionInfo.getFullName());
                    oplogApiVO.setClientId(sessionInfo.getClientId());
                    oplogApiVO.setUserType(sessionInfo.getUserType());
                    oplogApiVO.setEquipmentId(sessionInfo.getEquipmentId());
                    oplogApiVO.setLoginType(sessionInfo.getLoginType());
                    oplogApiVO.setEquipmentType(sessionInfo.getEquipmentType());
                    oplogApiVO.setOpenId(sessionInfo.getOpenId());
                    oplogApiVO.setSystemCode(sessionInfo.getSystemCode());
                    oplogApiVO.setSystemName(sessionInfo.getSystemName());
                    oplogApiVO.setVersion(sessionInfo.getVersion());
                }
            }
        }
        if (oplogApiVO.getEndTime()==null){
            oplogApiVO.setEndTime(new Date());
        }
        BigDecimal countTimeMs = new BigDecimal(oplogApiVO.getEndTime().getTime() - oplogApiVO.getBegTime().getTime());
        BigDecimal countTime = countTimeMs.divide(new BigDecimal(1000), 3, BigDecimal.ROUND_HALF_DOWN);
        oplogApiVO.setCountTime(countTime);
        if (StringUtils.isNotBlank(oplogApiVO.getMessage())&&oplogApiVO.getMessage().length()>400){
            oplogApiVO.setMessage(oplogApiVO.getMessage().substring(0,400));
        }
        OplogApi oplogApi = Convert.convert(OplogApi.class,oplogApiVO);
        oplogApiService.save(oplogApi);
    }

    @Override
    public Boolean saveChangeLog(Long oplogId, Object oldObj, Object newObj, Class classType, String opType, String opTable, String dataField) {
        if (oplogId==null){
            throw new AppException("日志id不能传空");
        }
        if (StringUtils.isBlank(opType)){
            throw new AppException("处理类型不能为空");
        }
        if (StringUtils.isBlank(opTable)){
            throw new AppException("处理的表不能为空");
        }
        if (StringUtils.isBlank(dataField)){
            throw new AppException("唯一标识字段不能为空");
        }
        if (classType==null){
            throw new AppException("处理的表实体类不能为空");
        }
        Oplog oplog = oplogService.getById(oplogId);
        if (oplog==null){
            throw new AppException("日志信息不存在("+oplogId+")");
        }
        List<OplogTableChange> insertList = new ArrayList<>();
        if (OpTypeEnum.ADD.getType().equalsIgnoreCase(opType)){
            if (newObj==null){
                throw new AppException("新增数据不能为空");
            }
            if (newObj instanceof java.util.List){
                List<Object> list= (List<Object>) newObj;
                for (Object obj:list){
                    insertList.add(createTableChange(obj,null,classType,dataField,oplog,opTable,opType));
                }
            }else {
                insertList.add(createTableChange(newObj,null,classType,dataField,oplog,opTable,opType));
            }
        }
        if (OpTypeEnum.EDIT.getType().equalsIgnoreCase(opType)){
            if (newObj==null){
                throw new AppException("修改后数据不能为空");
            }
            if (oldObj==null){
                throw new AppException("修改前数据不能为空");
            }
            Map<String,Object> oldMap = getOldMap(oldObj,dataField);
            if (newObj instanceof java.util.List){
                List<Object> list= (List<Object>) newObj;
                for (Object obj:list){
                    OplogTableChange oplogTableChange = createTableChange(obj,oldMap,classType,dataField,oplog,opTable,opType);
                    if (StringUtils.isNotBlank(oplogTableChange.getChangJson())){
                        insertList.add(oplogTableChange);
                    }
                }
            }else {
                OplogTableChange oplogTableChange = createTableChange(newObj,oldMap,classType,dataField,oplog,opTable,opType);
                if (StringUtils.isNotBlank(oplogTableChange.getChangJson())){
                    insertList.add(oplogTableChange);
                }
            }
        }
        if (OpTypeEnum.DEL.getType().equalsIgnoreCase(opType)||OpTypeEnum.DELETE.getType().equalsIgnoreCase(opType)){
            if (oldObj==null){
                throw new AppException("删除数据不能为空");
            }
            if (oldObj instanceof java.util.List){
                List<Object> list= (List<Object>) oldObj;
                for (Object obj:list){
                    insertList.add(createTableChange(obj,null,classType,dataField,oplog,opTable,opType));
                }
            }else {
                insertList.add(createTableChange(oldObj,null,classType,dataField,oplog,opTable,opType));
            }
        }
        if (!CollectionUtils.isEmpty(insertList)) {
            oplogTableChangeService.saveBatch(insertList);
            return true;
        }
        return false;
    }

    @Override
    public List<OplogChangeVO> toList(Class elementType, Long oplogId, String opTable) {
        return null;
    }

    private OplogTableChange createTableChange(Object obj,Map<String,Object> oldMap,Class classType,String dataField,Oplog oplog,String opTable,String opType){
        String uniqueValue = getUniqueValue(obj,dataField);
        OplogTableChange oplogTableChange = new OplogTableChange();
        Integer orderNo = 1;
        QueryWrapper<OplogTableChange> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(OplogTableChange::getLastFlag,BoolEnum.TRUE.getType())
                .eq(OplogTableChange::getDataType ,dataField)
                .eq(OplogTableChange::getUniqueValue,uniqueValue)
                .eq(OplogTableChange::getOpTable,opTable);
        OplogTableChange oldChange = oplogTableChangeService.getOne(queryWrapper);
        if (oldChange!=null){
            oplogTableChange.setSupChangeId(oldChange.getChangeId());
            if (oldChange.getOrderNo()!=null){
                orderNo = oldChange.getOrderNo()+1;
            }
            UpdateWrapper<OplogTableChange> upLast = new UpdateWrapper<>();
            upLast.lambda().set(OplogTableChange::getLastFlag,BoolEnum.FALSE.getType())
                    .eq(OplogTableChange::getChangeId,oldChange.getChangeId());
            oplogTableChangeService.update(upLast);
        }
        oplogTableChange.setOrderNo(orderNo);
        oplogTableChange.setTableJson(JSON.toJSONString(obj));
        oplogTableChange.setDataType(dataField);
        oplogTableChange.setBeanClassPath(classType.getName());
        oplogTableChange.setDateYm(oplog.getDateYm());
        oplogTableChange.setOplogId(oplog.getOplogId());
        oplogTableChange.setCreateTime(new Date());
        oplogTableChange.setStatus(BoolEnum.TRUE.getType());
        oplogTableChange.setOpTable(opTable);
        oplogTableChange.setLastFlag(BoolEnum.TRUE.getType());
        oplogTableChange.setOpType(opType);
        oplogTableChange.setUniqueValue(uniqueValue);
        if (OpTypeEnum.EDIT.getType().equalsIgnoreCase(opType)) {
            if (!CollectionUtils.isEmpty(oldMap)) {
                Object oldObj = oldMap.get(uniqueValue);
                if (oldObj == null) {
                    throw new AppException("变动前数据不能为空");
                }
                List<ModifiedFieldVO> changList = FieldChangeUtil.getModifyContentRemove(oldObj, obj, RemoveField.getBaseRemove());
                if (!CollectionUtils.isEmpty(changList)) {
                    oplogTableChange.setChangJson(JSON.toJSONString(changList));
                }
            }else {
                throw new AppException("变动前数据不能为空");
            }
        }
        return oplogTableChange;
    }

    private String getUniqueValue(Object obj,String dataField){
        if (obj==null){
            throw new AppException("处理数据不能为空");
        }
        BeanWrapper beanWrapper = new BeanWrapperImpl(obj);
        String uniqueValue = "";
        if (StringUtils.isNotBlank(dataField)){
            if (beanWrapper.isWritableProperty(dataField)){
                if (beanWrapper.getPropertyValue(dataField)!=null) {
                    uniqueValue=beanWrapper.getPropertyValue(dataField).toString();
                }
            }
        }else {
            throw new AppException("唯一标识所属字段名不能为空");
        }
        if (StringUtils.isBlank(uniqueValue)){
            throw new AppException("未获取到唯一字段值");
        }
        return uniqueValue;
    }
    private Map<String,Object> getOldMap(Object oldObj,String dataField){
        Map<String,Object> oldMap = new HashMap<>();
        if (oldObj instanceof java.util.List) {
            List<Object> list = (List<Object>) oldObj;
            for (Object old : list) {
                String oldValue = getUniqueValue(old, dataField);
                oldMap.put(oldValue, old);
            }
        }else {
            String oldValue = getUniqueValue(oldObj, dataField);
            oldMap.put(oldValue, oldObj);
        }
        return oldMap;
    }
}
